package com.yunhe.task.task;

import com.yunhe.common.model.data.PointNumberDTO;
import com.yunhe.task.client.DeviceClient;
import com.yunhe.task.client.MeasRealtimeClient;
import com.yunhe.common.constant.AuthorityConsts;
import com.yunhe.common.model.device.Analog;
import com.yunhe.common.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import zju.fes.exp.Calculator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class VirtualPointCalculateTask {

    @Autowired
    private MeasRealtimeClient measRealtimeClient;
    @Autowired
    private DeviceClient deviceClient;
    private static final String expressMatch = "(?<=\\()\\w+(?=\\))";
    private static final Calculator calculator = new Calculator();

    public void calculate() {
        //获得所有带公式的点号（TODO 改造成缓存）
        List<Analog> analogs = deviceClient.findAnalogsByFormulaNotNull().getBody().getResults();
        Map<Long, List<String>> fieldNameListMap = new HashMap<>();
        Map<Long, String> formulaMap = new HashMap<>();
        List<Long> pointNumbers = new ArrayList<>();
        if (analogs != null) {
            for (Analog analog : analogs) {
                String formula = analog.getFormula();
                formulaMap.put(analog.getPointNumber(), formula);
                //获得字段列表
                List<String> fieldNameList = StringUtil.getMatcherGroup(formula, expressMatch);
                fieldNameListMap.put(analog.getPointNumber(), fieldNameList);
                for (String fieldName : fieldNameList) {
                    Long pointNumber = Long.parseLong(fieldName);
                    if (!pointNumbers.contains(pointNumber)) {
                        pointNumbers.add(pointNumber);
                    }
                }
            }
        }
        //获得所有计算中需要的点号
        PointNumberDTO pointNumberDTO = new PointNumberDTO();
        pointNumberDTO.setPointNumbers(pointNumbers);
        Map<Long, Double> pointValueMap = measRealtimeClient.getMeasureRealtime(pointNumberDTO).getBody().getResults();

        Map<Long, Double> newPointValueMap = new HashMap<>();
        for (Map.Entry<Long, String> entry : formulaMap.entrySet()) {
            Long pointNumber = entry.getKey();
            String formula = entry.getValue();
            List<String> fieldNameList = fieldNameListMap.get(pointNumber);
            Map<String, Number> fieldsValue = new HashMap<>();
            boolean hasValue = true;
            for (String fieldName : fieldNameList) {
                Double value = pointValueMap.get(Long.parseLong(fieldName));
                if (value == null) {
                    hasValue = false;
                    break;
                }
                fieldsValue.put(fieldName, value);
            }
            //如果存在某个点号值为空的话，不进行计算
            if (hasValue) {
                try {
                    Double newValue = (Double) calculator.eval(formula, fieldsValue);
                    newPointValueMap.put(pointNumber, newValue);
                } catch (Exception e) {
                    continue;
                }
            }
        }

        //保存点号计算结果
        if (newPointValueMap.size() > 0) {
            measRealtimeClient.saveMeasureRealtimeAsync(newPointValueMap);
        }
    }
}
